package com.atguigu.tingshu.common.login;

import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.user.UserInfo;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @Author: hsl
 * @CreateTime: 2025-02-22  15:36
 */
@Component
@Aspect
@Slf4j
public class TsLoginAspect {
    @Resource
    private RedisTemplate redisTemplate;

    // 反射+AOP环绕通知 实现登录验证功能
    @Around("execution(* com.atguigu.tingshu.*.api.*.*(..)) && @annotation(tsLogin)")
    public Object tsLoginAspectAround(ProceedingJoinPoint proceedingJoinPoint, TsLogin tsLogin) {
        // 新建一个对象
        Object object = new Object();
        // 如何判断一个用户是否是进行登录
        // 系统如何处理登录请求
        /**
         * 1. 店调用微信小程序官方API
         * 2. 登录成功存储用户信息到redis中  并且返回一个token ，让前端获取并写到header 请求头中 便于后面使用
         */
        // 从请求头中获取token
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader("token");
        // 当需要进行登录时 用户若未进行登录则抛出异常
        if (tsLogin.required()) {
            //注解属性是判断token是否为空  是进行登录的时候用的
            if (StringUtils.isEmpty(token)) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            // 若不为空则从缓存中获取用户信息 并且判断用户数据是否为空
            String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
            UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(userLoginKey);
            // 判断userInfo 是否为空
            if (userInfo == null) {
                // 证明未登录  则抛出异常
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
        }
        try {
            // 如果token不为空
            if (!StringUtils.isEmpty(token)) {
                // 从缓存中会获取数据
                String userLoginKey1 = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
                UserInfo userInfo1 = (UserInfo) redisTemplate.opsForValue().get(userLoginKey1);
                // 判断userInfo
                if (null != userInfo1) {
                    // 缓存中有数据
                    AuthContextHolder.setUserId(userInfo1.getId());
                }
            }
            object = proceedingJoinPoint.proceed();
            // 返回数据
            return object;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        } finally {
            AuthContextHolder.removeUserId();
        }
    }

}
